home *** CD-ROM | disk | FTP | other *** search
- /*
- * This file is a contribution of David Tolpin (dvd@pizza.msk.su)
- * It is an implementation of BSD-INET sockets and is known to run on
- * Solaris 1 and Linux.
- *
- * (prepare-server-socket portnum)
- * bound socket to a local address. Returns an object of type socket-handle
- *
- * (release-server-socket! handle)
- * close server socket (created by prepare-server-socket
- *
- * (socket-handle? handle)
- * returns truth if the handle is of type socket-handle, false otherwise
- *
- * (listen-socket! handle)
- * listen for connection requests
- *
- * (accept-connection handle)
- * returns a new socket in response to a detected connection request,
- * the return value is a list of two ports,
- * - (car sp) is opened for reading,
- * - (cadr sp) - for writing
- *
- * (open-client-socket hostname portnum)
- * connect to a socket on a remote machine, returns the same data structure
- * as the function described above
- *
- * (shutdown-connection! skt)
- * shutdown socket, the mode of shutting down is determined according to
- * the mode of the port (read or write)
- */
-
- #include "stk.h"
- #include <errno.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netdb.h>
-
- PRIMITIVE prepare_server_socket(SCM portnum);
- PRIMITIVE release_server_socket(SCM handle);
- PRIMITIVE socket_handlep(SCM handle);
- PRIMITIVE listen_socket(SCM handle);
- PRIMITIVE accept_connection(SCM handle);
- PRIMITIVE open_client_socket(SCM hostname, SCM portnum);
- PRIMITIVE shutdown_connection(SCM skt);
-
- /*
- : stk_socket.c,v 1.4 1994/06/26 19:14:55 dvd Exp dvd $
- */
-
- /*
- : stk_socket.c,v $
- * Revision 1.4 1994/06/26 19:14:55 dvd
- * *** empty log message ***
- *
- * Revision 1.3 1994/06/26 18:55:27 dvd
- * Verbose error reporting is added
- *
- */
-
- #ifdef __sun__
- extern char *sys_errlist[];
- #endif
-
- struct socket_handle {
- int portnum;
- char *hostname;
- int handle;
- };
-
- static int tc_sockhandle;
-
- static void free_sockhandle(SCM handle);
- static void mark_sockhandle(SCM handle);
- static void displ_sockhandle(SCM x, FILE *f, int mode);
-
- static extended_scheme_type sockhandle_type = {
- "sockhandle", /* name */
- 0, /* is_procp */
- mark_sockhandle, /* gc_mark_fct */
- free_sockhandle, /* gc_free_fct */
- NULL, /* apply_fct */
- displ_sockhandle /* display_fct */
- };
-
-
- #define SOCKHANDLE(x) ((struct socket_handle*)(x->storage_as.extension.data))
- #define LSOCKHANDLE(x) (x->storage_as.extension.data)
- #define SOCKHANDLEP(x) (TYPEP(x,tc_sockhandle))
- #define NSOCKHANDLEP(x) (NTYPEP(x,tc_sockhandle))
-
- void mark_sockhandle(SCM handle)
- {
- }
-
- void free_sockhandle(SCM handle)
- {
- struct socket_handle *sh;
- sh = SOCKHANDLE(handle);
- if(sh->hostname) free(sh->hostname);
- close(sh->handle);
- free(sh);
- LSOCKHANDLE(handle) = NULL;
- }
-
- void displ_sockhandle(SCM handle, FILE *f, int mode)
- {
- struct socket_handle *sh;
- sh = SOCKHANDLE(handle);
- sprintf(tkbuffer, "#[socket-handle %s %i]", sh->hostname, sh->portnum);
- Puts(tkbuffer,f);
- }
-
-
- static SCM makesp(int s, char *hn, int portnum)
- {
- int t;
- int hnlen;
- FILE *fs, *ft;
- SCM zs, zt;
- long flag;
-
- flag = no_interrupt(1);
-
- t = dup(s); /* duplicate handles so that we are able to access one socket channel */
- /* via two scheme ports */
- if(!((fs = fdopen(s, "r")) && (ft = fdopen(s, "w"))))
- err("internal(makesp): cannot create ports", NIL);
- NEWCELL(zs, tc_iport);
- NEWCELL(zt, tc_oport);
- zs->storage_as.port.f = fs; setbuf(fs, NULL); /* unbuffered input/output */
- zt->storage_as.port.f = ft; setbuf(ft, NULL);
- zs->storage_as.port.name = (char*)must_malloc((hnlen = strlen(hn))+16);
- sprintf(zs->storage_as.port.name, "%s:%i(r)", hn, portnum);
- zt->storage_as.port.name = (char*)must_malloc((hnlen = strlen(hn))+16);
- sprintf(zt->storage_as.port.name, "%s:%i(w)", hn, portnum);
-
- no_interrupt(flag);
- return(cons(zs, cons(zt, NIL)));
- }
-
- PRIMITIVE prepare_server_socket(SCM portnum)
- {
- struct sockaddr_in sin;
- int s;
- long flag;
- SCM ys;
-
- if(NINTEGERP(portnum))
- err("not a port number", portnum);
- sin.sin_port = INTEGER(portnum);
- sin.sin_addr.s_addr = INADDR_ANY;
- if((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- err(sys_errlist[errno], portnum);
- if(bind(s, (struct sockaddr*)&sin, sizeof sin) < 0)
- switch(errno) {
- case EADDRINUSE:
- case EADDRNOTAVAIL: {
- SCM errcode;
- NEWCELL(errcode, tc_integer);
- SET_INTEGER(errcode, errno);
- return errcode;
- }
- break;
- default: err(sys_errlist[errno], portnum);
- }
- /* now we're ready to create the object */
- NEWCELL(ys, tc_sockhandle);
- LSOCKHANDLE(ys) = (struct socket_handle*)must_malloc(sizeof (struct socket_handle));
- SOCKHANDLE(ys)->portnum = sin.sin_port;
- SOCKHANDLE(ys)->hostname = (char*)must_malloc(strlen("localhost")+1);
- strcpy(SOCKHANDLE(ys)->hostname, "localhost");
- SOCKHANDLE(ys)->handle = s;
-
- return ys;
- }
-
-
- PRIMITIVE release_server_socket(SCM handle)
- {
- if(NSOCKHANDLEP(handle)) err("not a socket handle", handle);
- close(SOCKHANDLE(handle)->handle);
- return UNDEFINED;
- }
-
- PRIMITIVE socket_handlep(SCM handle)
- {
- return SOCKHANDLEP(handle)? truth: ntruth;
- }
-
- PRIMITIVE listen_socket(SCM handle)
- {
- if(NSOCKHANDLEP(handle))
- err("not a socket handle", handle);
- if(listen(SOCKHANDLE(handle)->handle, 5) < 0)
- err(sys_errlist[errno], handle);
- return UNDEFINED;
- }
-
- PRIMITIVE accept_connection(SCM handle)
- {
- int s;
-
- if(NSOCKHANDLEP(handle))
- err("not a socket handle", handle);
- if((s = accept(SOCKHANDLE(handle)->handle, NULL, NULL)) < 0)
- err(sys_errlist[errno], handle);
- return makesp(s, SOCKHANDLE(handle)->hostname, SOCKHANDLE(handle)->portnum);
- }
-
- PRIMITIVE open_client_socket(SCM hostname, SCM portnum)
- {
- char *hn;
- struct hostent *hp;
- struct sockaddr_in server;
- int s;
-
- if(NSTRINGP(hostname)) err("bad hostname", hostname);
- if(NINTEGERP(portnum)) err("bad port number", portnum);
- hp = gethostbyname(hn = CHARS(hostname));
- if(!hp) err("unknown or misspelled host name", hostname);
- bzero((char*)&server,sizeof server);
- bcopy(hp->h_addr,(char*)&server.sin_addr, hp->h_length);
- server.sin_family = hp->h_addrtype;
- server.sin_port = INTEGER(portnum);
- if((s = socket(AF_INET,SOCK_STREAM,0)) < 0)
- err(sys_errlist[errno], NIL);
- if(connect(s, (struct sockaddr *)&server, sizeof server) < 0)
- switch(errno) {
- case EADDRINUSE:
- case EADDRNOTAVAIL:
- case ETIMEDOUT:
- case ECONNREFUSED: {
- SCM errcode;
- NEWCELL(errcode, tc_integer);
- SET_INTEGER(errcode, errno);
- return errcode;
- }
- break;
- default: err(sys_errlist[errno], NIL);
- }
- return makesp(s, hn, server.sin_port);
- }
-
- PRIMITIVE shutdown_connection(SCM skt)
- {
- if(NIPORTP(skt) && NOPORTP(skt))
- err("not a port", skt);
- if(shutdown(fileno(skt->storage_as.port.f), IPORTP(skt)?0:1) < 0)
- err(sys_errlist[errno], NIL);
- return UNDEFINED;
- }
-
- void init_socket(void)
- {
- tc_sockhandle = add_new_type(&sockhandle_type);
-
- add_new_primitive("prepare-server-socket", tc_subr_1, prepare_server_socket);
- add_new_primitive("release-server-socket!", tc_subr_1, release_server_socket);
- add_new_primitive("socket-handle?", tc_subr_1, socket_handlep);
- add_new_primitive("listen-socket!", tc_subr_1, listen_socket);
- add_new_primitive("accept-connection", tc_subr_1, accept_connection);
- add_new_primitive("open-client-socket", tc_subr_2, open_client_socket);
- add_new_primitive("shutdown-connection!", tc_subr_1, shutdown_connection);
- };
-
-